package cn.jbolt.core.poi.excel;

import cn.hutool.core.date.DateUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Okv;
import com.jfinal.kit.StrKit;
import com.jfinal.kit.TimeKit;
import com.jfinal.plugin.activerecord.CPI;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.Temporal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Supplier;

/**
 * JBolt Excel 数据
 *
 * @ClassName: JBoltExcelData
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2020年3月10日
 */
@SuppressWarnings("serial")
public class JBoltExcelData extends HashMap<String, Object> {
	public JBoltExcelData(Map<String, Object> datas) {
		this.putAll(datas);
	}

	/**
	 * 数据来自model
	 *
	 * @param model
	 * @return
	 */
	public static JBoltExcelData fromModel(Model<?> model) {
		return fromMap(CPI.getAttrs(model));
	}

	/**
	 * 数据来自Record
	 *
	 * @param record
	 * @return
	 */
	public static JBoltExcelData fromRecord(Record record) {
		return fromMap(record.getColumns());
	}

	/**
	 * 数据来自map
	 *
	 * @param mapData
	 * @return
	 */
	public static JBoltExcelData fromMap(Map<String, Object> mapData) {
		return new JBoltExcelData(mapData);
	}

	public <T> T getAs(Object key) {
		return (T) get(key);
	}

	public String getStr(Object key) {
		Object s = get(key);
		return s != null ? s.toString() : null;
	}

	public Integer getInt(Object key) {
		Number n = getNumber(key);
		return n != null ? n.intValue() : null;
	}

	public Long getLong(Object key) {
		Number n = getNumber(key);
		return n != null ? n.longValue() : null;
	}

	public Date getDate(Object key) {
		Object ret = get(key);
		if (ret == null) {
			return null;
		}
		if (ret instanceof String) {
			return cn.jbolt.core.util.JBoltDateUtil.getDate(ret.toString());
		}
		if (ret instanceof Temporal) {
			if (ret instanceof LocalDateTime) {
				return TimeKit.toDate((LocalDateTime) ret);
			}
			if (ret instanceof LocalDate) {
				return TimeKit.toDate((LocalDate) ret);
			}
			if (ret instanceof LocalTime) {
				return TimeKit.toDate((LocalTime) ret);
			}
		}

		return (Date) ret;
	}

	public Number getNumber(Object key) {
		return getAs(key);
	}

	public Boolean getBoolean(Object key) {
		return getAs(key);
	}

	/**
	 * key 存在，并且 value 不为 null
	 */
	public boolean notNull(Object key) {
		return get(key) != null;
	}

	/**
	 * key 不存在，或者 key 存在但 value 为null
	 */
	public boolean isNull(Object key) {
		return get(key) == null;
	}

	/**
	 * key 存在，并且 value 为 true，则返回 true
	 */
	public boolean isTrue(Object key) {
		String value = getStr(key);
		if (StrKit.isBlank(value)) {
			return false;
		}
		return value.equals("1") || value.equalsIgnoreCase("true") || value.equalsIgnoreCase("是");
	}

	/**
	 * key 存在，并且 value 为 false，则返回 true
	 */
	public boolean isFalse(Object key) {
		String value = getStr(key);
		if (StrKit.isBlank(value)) {
			return true;
		}
		return value.equals("0") || value.equalsIgnoreCase("false") || value.equalsIgnoreCase("否");
	}

	/**
	 * 改变数据
	 *
	 * @param key
	 * @param value
	 */
	public void change(String key, Object value) {
		put(key, value);
	}

	/**
	 * 替换Date数据 转为其他字符串
	 *
	 * @param key
	 * @param formatPattern
	 */
	public void changeDateToStr(String key, String formatPattern) {
		if (notNull(key)) {
			Date date = getDate(key);
			if (date != null) {
				change(key, DateUtil.format(date, formatPattern));
			}
		}
	}

	/**
	 * 替换boolean数据 转为其他字符串
	 *
	 * @param key
	 * @param trueStr
	 * @param falseStr
	 */
	public void changeBooleanToStr(String key, String trueStr, String falseStr) {
		if (isNull(key)) {
			change(key, falseStr);
		} else {
			if (isTrue(key)) {
				change(key, trueStr);
			} else if (isFalse(key)) {
				change(key, falseStr);
			}
		}
	}

	/**
	 * 转换string to bool
	 *
	 * @param key
	 * @param kv
	 */
	public void changeStrToBoolean(String key, Kv kv) {
		String value = getStr(key);
		change(key, value != null && kv.getBoolean(value));
	}

	/**
	 * 转换string to bool
	 *
	 * @param key
	 * @param trueStr
	 */
	public void changeStrToBoolean(String key, String trueStr) {
		String value = getStr(key);
		change(key, (trueStr.equalsIgnoreCase(value)));
	}

	/**
	 * 连带KEY一并change
	 *
	 * @param oldKey
	 * @param newKey
	 * @param newValue
	 */
	public void changeWithKey(String oldKey, String newKey, Object newValue) {
		remove(oldKey);
		put(newKey, newValue);
	}

	/**
	 * 连带KEY一并change
	 *
	 * @param oldKey
	 * @param newKey
	 * @param supplier
	 */
	public void changeWithKey(String oldKey, String newKey, Supplier<?> supplier) {
		remove(oldKey);
		put(newKey, supplier.get());
	}

	/**
	 * 数据来自Kv
	 *
	 * @param kv
	 * @return
	 */
	public static JBoltExcelData fromKv(Kv kv) {
		return fromMap(kv);
	}


	/**
	 * 数据来自Okv
	 *
	 * @param okv
	 * @return
	 */
	public static JBoltExcelData fromOkv(Okv okv) {
		return fromMap(okv);
	}


	/**
	 * 按照列下标Index获取数据
	 *
	 * @param <T>
	 * @param colIndex
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getByIndexAs(int colIndex) {
		Iterator<Entry<String, Object>> iterator = this.entrySet().iterator();
		Entry<String, Object> t = null;
		int i = 0;
		while (iterator.hasNext()) {
			t = iterator.next();
			if (i == colIndex) {
				break;
			}
			i++;
		}
		assert t != null;
		return (T) (t.getValue());
	}

	/**
	 * 按照列下标Index获取数据 Integer类型
	 *
	 * @param colIndex
	 * @return
	 */
	public Integer getIntByIndex(int colIndex) {
		Number n = getNumberByIndex(colIndex);
		return n != null ? n.intValue() : null;
	}

	/**
	 * 按照列下标Index获取数据 Long类型
	 *
	 * @param colIndex
	 * @return
	 */
	public Long getLongByIndex(int colIndex) {
		Number n = getNumberByIndex(colIndex);
		return n != null ? n.longValue() : null;
	}

	/**
	 * 按照列下标Index获取数据 Long类型
	 *
	 * @param colIndex
	 * @return
	 */
	public Number getNumberByIndex(int colIndex) {
		return getByIndexAs(colIndex);
	}

	/**
	 * 按照列下标Index获取数据 Boolean类型
	 *
	 * @param colIndex
	 * @return
	 */
	public Boolean getBooleanByIndex(int colIndex) {
		return getByIndexAs(colIndex);
	}

	/**
	 * 按照列下标Index获取数据 String类型
	 *
	 * @param colIndex
	 * @return
	 */
	public String getStrByIndex(int colIndex) {
		Object value = getObjectValueByIndex(colIndex);
		return value != null ? value.toString() : null;
	}

	/**
	 * 按照列下标 获取单元格Object value
	 *
	 * @param colIndex
	 * @return
	 */
	public Object getObjectValueByIndex(int colIndex) {
		Iterator<Entry<String, Object>> iterator = this.entrySet().iterator();
		Entry<String, Object> t = null;
		int i = 0;
		while (iterator.hasNext()) {
			t = iterator.next();
			if (i == colIndex) {
				break;
			}
			i++;
		}
		assert t != null;
		return t.getValue();
	}

	/**
	 * changeHandler执行
	 *
	 * @param changeHandler
	 * @param index
	 * @return
	 */
	public JBoltExcelData change(JBoltExcelDataChangeHandler changeHandler, int index) {
		if (changeHandler != null) {
			changeHandler.change(this, index);
		}
		return this;
	}

}
